package day20171118;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by 14394 on 2017/11/18.
 */
public class TestAntiJsoup {
    public static void main(String[] args) throws IOException, URISyntaxException {

        //伪装请求头
        Map<String, String> header = new HashMap<String, String>();
        header.put("Host", "x.autoimg.cn");
        header.put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0");
        header.put("Accept", "	text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        header.put("Accept-Language", "zh-cn,zh;q=0.5");
        header.put("Accept-Charset", "	GB2312,utf-8;q=0.7,*;q=0.7");
        header.put("Connection", "keep-alive");



        Document d= Jsoup.connect("http://club.autohome.com.cn/bbs/threadqa-c-3980-68373466-1.html").data(header).get();
        //Document d= Jsoup.connect("https://club.autohome.com.cn/bbs/thread-c-3170-68533465-1.html").get();
        //System.out.println(d.text());



        Element content= d.select(".rconten").first();
        //System.out.println(content.html());
        String articleHtml=content.html();

        String script=content.select("script").first().html();
        //处理混淆的js代码
        //判断混淆， 无参数 返回常量的代码翻译成el表达式
        //如：下面的代码原型：function Ad_() { function _A() { return 'Ad__'; };
        // if (_A() == 'Ad__') { return '8'; } else { return _A(); } }
        //意为取出每个混淆 无参数 返回常量 函数 格式的函数
    String regex1="function\\s*(\\w+)\\(\\)\\s*\\{\\s*" + "function\\s+\\w+\\(\\)\\s*\\{\\s*"
            + "return\\s+[\'\"]([^\'\"]+)[\'\"];\\s*" + "\\};\\s*"
            + "if\\s*\\(\\w+\\(\\)\\s*==\\s*[\'\"]([^\'\"]+)[\'\"]\\)\\s*\\{\\s*"
            + "return\\s*[\'\"]([^\'\"]+)[\'\"];\\s*" + "\\}\\s*else\\s*\\{\\s*" + "return\\s*\\w+\\(\\);\\s*"
            + "\\}\\s*" + "\\}";
        Pattern p1=Pattern.compile(regex1);
        Matcher m1=p1.matcher(script);
        //找出所有匹配上面条件的函数，存入List
        List<String>  l1=new ArrayList<String>();
        while (m1.find()){
            //Matcher.group(int i) 方法可以获取正则表达式中的第i个括号里的内容
            l1.add(m1.group());

        }
        for (String str:l1){
            Pattern pl1=Pattern.compile(regex1);
            Matcher ml1=pl1.matcher(str);
            while (ml1.find()){
                String name=ml1.group(1);//获取第一个括号里面的内容
                String b=ml1.group(2);
                String c=ml1.group(3);
                String value="";
                if (b.equals(c)){
                    value=ml1.group(4);
                }else {
                    value=ml1.group(2);
                }
                script=script.replaceAll(name+"\\(\\)",value);//给name 的正则加上括号
            }
        }

        //2取出每个  混淆 无参数 返回函数 常量 格式的函数

        String regex2 = "function\\s*(\\w+)\\(\\)\\s*\\{\\s*" + "function\\s*\\w+\\(\\)\\s*\\{\\s*"
                + "return\\s*[\'\"]([^\'\"]+)[\'\"];\\s*" + "\\};\\s*"
                + "if\\s*\\(\\w+\\(\\)\\s*==\\s*[\'\"]([^\'\"]+)[\'\"]\\)\\s*\\{\\s*" + "return\\s*\\w+\\(\\);\\s*"
                + "\\}\\s*else\\s*\\{\\s*" + "return\\s*[\'\"]([^\'\"]+)[\'\"];\\s*" + "\\}\\s*" + "\\}";
        Pattern p2 = Pattern.compile(regex2);
        Matcher m2 = p2.matcher(script);
        // 找出所有匹配的字符串,存入List中
        List<String> l2 = new ArrayList<String>();
        while (m2.find()) {
            l2.add(m2.group());

        }
        for (String str : l2) {
            Pattern p21 = Pattern.compile(regex2);
            Matcher m21 = p21.matcher(str);
            while (m21.find()) {
                String name = m21.group(1);// 获取第一个括号里的内容
                String b = m21.group(2);
                String c = m21.group(3);
                String value = "";
                if (!b.equals(c)) {
                    value = m21.group(4);
                } else {
                    value = m21.group(2);
                }
                script = script.replaceAll(name + "\\(\\)", value);
            }
        }

    //3取出 var参数等于返回值类型的函数

        String regex3 = "var\\s*([^=]+)\\s*=\\s*function\\(\\w+\\)\\{\\s*" + "[\'\"]return\\s*\\w+\\s*[\'\"];\\s*"
                + "return\\s+\\w+;\\s*" + "\\};";
        Pattern p3 = Pattern.compile(regex3);
        Matcher m3 = p3.matcher(script);
        // 找出所有匹配的字符串,存入List中
        List<String> l3 = new ArrayList<String>();
        while (m3.find()) {
            l3.add(m3.group());

        }
        for (String str : l3) {
            Pattern p31 = Pattern.compile(regex3);
            Matcher m31 = p31.matcher(str);
            while (m31.find()) {
                String name31 = m31.group(1);
                // 再次利用正则,在js中截取ZA__(',5_198')
                String regex32 = name31 + "\\(([^\\)]+)\\)";
                Pattern p32 = Pattern.compile(regex32);
                Matcher m32 = p32.matcher(script);
                while (m32.find()) {
                    String value32 = m32.group(1);
                    script = script.replaceAll(regex32, value32);
                }
            }

        }

        //4取出  var 无参数 返回常量 函数的 函数

        String regex4 = "var\\s*([^=]+)=\\s*function\\(\\)\\s*\\{\\s*" + "[\'\"]return\\s*\\w+\\s*[\'\"];\\s*"
                + "return\\s*[\'\"]([^\'\"]+)[\'\"];\\s*" + "\\};";
        Pattern p4 = Pattern.compile(regex4);
        Matcher m4 = p4.matcher(script);
        // 找出所有匹配的字符串,存入List中
        List<String> l4 = new ArrayList<String>();
        while (m4.find()) {
            l4.add(m4.group());

            /*
             * String name4 = m4.group(1);//获取第一个括号里的内容 String value4 =
             * m4.group(2);//获取第一个括号里的内容 script =
             * script.replaceAll(name4+"\\(\\)", value4);
             */
        }
        for (String str4 : l4) {
            Pattern p41 = Pattern.compile(regex4);
            Matcher m41 = p41.matcher(str4);
            while (m41.find()) {
                String name41 = m41.group(1);// 获取第一个括号里的内容
                String value41 = m41.group(2);// 获取第一个括号里的内容
                script = script.replaceAll(name41 + "\\(\\)", value41);
            }
        }

        //5.取出 无参数 返回常量 函数的函数

        String regex5 = "function\\s*(\\w+)\\(\\)\\s*\\{\\s*" + "[\'\"]return\\s*[^\'\"]+[\'\"];\\s*"
                + "return\\s*[\'\"]([^\'\"]+)[\'\"];\\s*" + "\\}\\s*";
        Pattern p5 = Pattern.compile(regex5);
        Matcher m5 = p5.matcher(script);
        // 找出所有匹配的字符串,存入List中
        List<String> l5 = new ArrayList<String>();
        while (m5.find()) {
            l5.add(m5.group());

        }
        // 遍历每一条匹配到的字符串
        for (String str5 : l5) {
            Pattern p51 = Pattern.compile(regex5);
            Matcher m51 = p51.matcher(str5);
            while (m51.find()) {
                String name51 = m51.group(1);// 获取第一个括号里的内容,也就是HB_
                String value51 = m51.group(2);// 获取第二个括号里的内容,也就是-;
                String regex51 = name51 + "\\(\\)";// 组合HB_()的正则表达式
                script = script.replaceAll(regex51, value51);
            }

        }

        //6取出 无参数 返回常量 函数  中间无混淆代码的 函数

        String regex6 = "function\\s*(\\w+)\\(\\)\\s*\\{\\s*" + "return\\s*[\'\"]([^\'\"]*)[\'\"];\\s*" + "\\}\\s*";
        Pattern p6 = Pattern.compile(regex6);
        Matcher m6 = p6.matcher(script);
        // 找出所有匹配的字符串,存入List中
        List<String> l6 = new ArrayList<String>();
        while (m6.find()) {
            l6.add(m6.group());
        }
        for (String str6 : l6) {
            Pattern p61 = Pattern.compile(regex6);
            Matcher m61 = p61.matcher(str6);
            while (m61.find()) {
                String name61 = m61.group(1);
                String value6 = m61.group(2);
                String regex61 = name61 + "\\(\\)";
                script = script.replaceAll(regex61, value6);
            }
        }

        //7取出字符串拼接时 无参常量的函数
        String regex7 = "\\(function\\(\\)\\s*\\{\\s*" + "[\'\"]return[^\'\"]+[\'\"];\\s*"
                + "return\\s*([\'\"][^\'\"]*[\'\"]);?\\s*" + "\\}\\)\\(\\)";
        Pattern p7 = Pattern.compile(regex7);
        Matcher m7 = p7.matcher(script);
        // 找出所有匹配的字符串,存入List中
        List<String> l7 = new ArrayList<String>();
        while (m7.find()) {
            l7.add(m7.group());

        }
        // 遍历每一个匹配的字符串,并替换为实际的值
        for (String str7 : l7) {
            Pattern p71 = Pattern.compile(regex7);
            Matcher m71 = p71.matcher(str7);
            while (m71.find()) {
                String value7 = m71.group(1);
                script = script.replace(str7, value7);

            }
        }

        //8取出字符串拼接时 使用返回参数 的函数

        // 8.字符串拼接时使用返回参数的函数
        /*
         * 类似于以下这种结构 (function(eR__) { 'return eR_'; return eR__; })('%9')
         * 将整体替换为%9
         */

        String regex8 = "\\(function\\(\\w+\\)\\s*\\{\\s*" + "[\'\"]return[^\'\"]+[\'\"];\\s*" + "return\\s*\\w+;\\s*"
                + "\\}\\)\\(([\'\"][^\'\"]*[\'\"])\\)";
        Pattern p8 = Pattern.compile(regex8);
        Matcher m8 = p8.matcher(script);
        // 找出所有匹配的字符串,存入List中
        List<String> l8 = new ArrayList<String>();
        while (m8.find()) {
            l8.add(m8.group());

        }
        // 遍历每一个匹配的字符串,并替换为实际的值
        for (String str8 : l8) {
            Pattern p81 = Pattern.compile(regex8);
            Matcher m81 = p81.matcher(str8);
            while (m81.find()) {
                String value8 = m81.group(1);
                script = script.replace(str8, value8);

            }
        }

        //9取出所有  var pz_=''格式的变量
        Pattern p = Pattern.compile("var \\w+=\'.*?\'");
        Matcher m = p.matcher(script);
        while (m.find()) {
            if (m.group().contains("<")) {
                continue;
            }
            // System.out.println(m.group());
            String varName = m.group().split(" ")[1].split("=")[0];
            String varValue = m.group().split(" ")[1].split("=")[1].replaceAll("'", "");
            script = script.replaceAll(varName, varValue);
        }


        // 将js中所有的空格,+,',都去掉
        script = script.replaceAll("[\\s+']", "");

        //10  取出所有的字符，进行转码

        Pattern p10=Pattern.compile("((?:%\\w\\w)+)");
        Matcher m10=p10.matcher(script);
        String[] words={};
        while (m10.find()){
            String result= new URI(m10.group()).getPath();
            words=result.split("");

        }

        //11 从字符密集区域后面开始寻找索引区域，连续匹配十次以上，确保是索引
        //但是当页面中替换的内容较少时，则得不到结果
//        Pattern p11=Pattern.compile("([\\d,]+(;[\\d,]+)+){10,}");
//        //Pattern p11=Pattern.compile("([\\d,]+(;[\\d,]+)+)");
//        Matcher m11=p11.matcher(script);
//        System.out.println(script);
//        String[] indexes={};
//        while (m11.find()){
//            indexes=m11.group().split("[;,]");
//            System.out.println(m11.group());
//        }
//
//        System.out.println(indexes.length);
        //if (indexes.length==0){}

        //我的改进
        //1 得到所有待解码的文字，其后方紧接着便是编码索引的函数
       Pattern p21=Pattern.compile("((?:%\\w\\w)+(\\w+\\(\\)))");
        Matcher m21=p21.matcher(script);
        //找到该函数后进行格式化，提取出要的信息
        String s=null;
        while (m21.find()){
            s=m21.group();
            s=s.substring(s.lastIndexOf("%")+3,s.lastIndexOf("("));
          //  System.out.println(s);
        }

        Pattern p22=Pattern.compile("\\("+s+"\\(\\)[\\d,]*[,;\\d]*[\\d,]+\\)");
        Matcher m22=p22.matcher(script);
        String[] indexes={};
        while (m22.find()){
            //格式化得到的信息
            String ss=m22.group();
          //  System.out.println(ss);
            if(ss.split("[;,]").length>1){
                ss=ss.substring(ss.indexOf(";")-1,ss.lastIndexOf(")"));
                indexes=ss.split("[;,]");
            }else {
                ss=ss.substring(ss.indexOf(")")+1,ss.lastIndexOf(")"));
                String[] theOne={ss};
                indexes=theOne;
            }
        }

        //至此，将替换的子全部显示出来
        //漏洞：可能存在字符串重复的情况


        //至此，js中的混淆解决完成
        //###########################################
        //############################################
        //开始替换<span>标签
        //通过<span>标签的class属性里面的数字进行替换
        Pattern p12=Pattern.compile("<span\\s*class=[\'\"]hs_kw(\\d+)_([^\'\"]+)[\'\"]></span>");
        Matcher m12=p12.matcher(articleHtml);
        while (m12.find()){
            //得到某一类型的编码的索引
            int num=Integer.parseInt(m12.group(1));
            //以class属性中的数字为下标，寻找相应的索引号
            String index=indexes[num];
            int indexWord=Integer.parseInt(index);
            //获取每个<span>对应的文字
            String word=words[indexWord];
            articleHtml=articleHtml.replace(m12.group(),word);
        }
        Document articleDoc=Jsoup.parse(articleHtml);
        String article=articleDoc.text().replaceAll(" ","");
        System.out.println(article);

    }
}
